﻿using KinonekoSoftware.CodariaDB.Documents.Templates;
using KinonekoSoftware.CodariaDB.Utils;
using KinonekoSoftware.Studio.Models.Theories;
using KinonekoSoftware.Studio.Utils;
using TagLib.Riff;

namespace KinonekoSoftware.Studio.Pages.Theories
{
    partial class WorldViewConfigViewModel
    {

        //-------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------
        private Dictionary<string, TreeCatalog> CatalogMap;
        private HashSet<string>                 NameMap;

        private TreeCatalog      _currentTreeCatalog;
        private InstanceTemplate _currentTreeCatalogCustomTemplate;


        //-------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------

        private void Initialize()
        {
            //
            //
            _appCatalogRoot = _repository.GetOrCreate<CatalogRoot>(CatalogRoot.CreateCatalogsVersion2, false);

            //
            //
            var rebuild = ArrayRebuild.RebuildCatalogs(_appCatalogRoot.Catalogs, out CatalogMap);

            //
            //
            NameMap = new HashSet<string>(_appCatalogRoot.Catalogs
                                                         .Where(x => string.IsNullOrEmpty(x.ParentID))
                                                         .Select(x => x.Name));


            TreeCatalogs.AddMany(rebuild, true);
            CurrentTreeCatalog = TreeCatalogs.FirstOrDefault();
        }

        private void SaveTreeCatalogs()
        {

            _repository.Set(_appCatalogRoot);
        }


        private async void AfterUseCustomType(bool value)
        {
            //
            // 如果自定义设定模板为空
            if (CustomTypeInstanceTemplates.Count == 0)
            {
                //
                //
                await Warning(TitleSR.WarningOperation, "当前没有可用的自定义设定模板，请先在【设定模板】页面创建模板之后再使用！");
                
                //
                // 取消使用自定义模板
                CurrentTreeCatalog.UseCustomType = false;
                return;
            }

            if (value && CustomTypeInstanceTemplates.Count == 1)
            {
                CurrentTreeCatalogCustomType = CustomTypeInstanceTemplates[0].CustomType;
            }
        }

        //-------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------

        private void DoApplyCatalogChangedCommand()
        {
            SaveTreeCatalogs();
            Queue.OnNext(new ApplyCatalogChangedMessage());
        }


        private async void DoNewTreeCatalogCommand(TreeCatalog parent)
        {
            var r = await SingleText("新建文件夹", "输入要创建的文件夹名字");

            if (!r.IsFinished)
            {
                return;
            }

            var val = r.Value;
            var id  = ID.Get();
            var catalog = new TreeCatalog
            {
                Id          = id,
                Name        = val,
                IsVisible   = true,
            };


            if (parent is null)
            {
                //
                // 只有顶级目录，会要求不能同名
                if (!NameMap.Add(val))
                {
                    await Danger(TitleSR.DangerOperation, "文件夹的名字与先有的文件夹重复");
                    return;
                }

                //
                // 
                TreeCatalogs.Add(catalog);
                _appCatalogRoot.Catalogs.Add(catalog);

                for (var i = 0; i < TreeCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index                = i;
                    _appCatalogRoot.Catalogs[i].Index = i;
                }
            }
            else
            {
                catalog.ParentID = parent.Id;
                parent.Children.Add(catalog);

                for (var i = 0; i < parent.Children.Count; i++)
                {
                    parent.Children[i].Index = i;
                }
                _appCatalogRoot.Catalogs.Add(catalog);
            }

            //
            //
            Save();

        }

        private async void DoMoveTreeCatalogCommand(TreeCatalog element)
        {
            if (element is null)
            {
                return;
            }

            var context = new DialogContext();
            var target = new PseudoCatalog
            {
                Id              = element.Id,
                Children        = new ObservableCollection<PseudoCatalog>(),
                ParentID        = element.ParentID,
                Name            = element.Name,
                IsTargetCatalog = true,
            };


            var rebuild = ArrayRebuild.Rebuild(_appCatalogRoot.Catalogs
                                                              .Select(x => new PseudoCatalog
                                                               {
                                                                   Id       = x.Id,
                                                                   ParentID = x.ParentID,
                                                                   Name     = x.Name,
                                                                   Children = new ObservableCollection<PseudoCatalog>(),
                                                               }).Where(x => x.Id != element.Id)
                                                              .ToList(), out var pseudoCatalogMap);

            context.Set(MoveCatalogViewModel.PseudoCatalogs, rebuild);
            context.Set(MoveCatalogViewModel.PseudoCatalogMap, pseudoCatalogMap);
            context.Set(MoveCatalogViewModel.TargetElement, target);

            var r = await Dialog<PseudoCatalog, MoveCatalogViewModel>(context);

            if (!r.IsFinished)
            {
                return;
            }

            //
            // final done

            if (element.ParentID == target.ParentID && target.Index == element.Index)
            {
                return;
            }


            // remove default catalog
            RemoveOldPosition(element);
            MoveToNewPosition(element, target.ParentID, target.Index);


            //
            //
            Save();
        }

        private void RemoveOldPosition(TreeCatalog catalog)
        {
            if (catalog.IsRoot())
            {
                TreeCatalogs.Remove(catalog);
                _appCatalogRoot.Catalogs.Remove(catalog);
            }
            else if (CatalogMap.TryGetValue(catalog.ParentID, out var parent))
            {
                parent.Children.Remove(catalog);
            }
        }

        private async void MoveToNewPosition(TreeCatalog catalog, string newParentId, int index)
        {
            // 移动到根目录
            if (string.IsNullOrEmpty(newParentId))
            {
                TreeCatalogs.Insert(index, catalog);
                for (var i = 0; i < TreeCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index = i;
                }
            }
            else if (CatalogMap.TryGetValue(newParentId, out var newParent))
            {
                newParent.Children.Insert(index, catalog);

                for (var i = 0; i < newParent.Children.Count; i++)
                {
                    newParent.Children[i].Index = i;
                }
            }

            //
            // set new parent id
            catalog.ParentID = newParentId;
            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);
        }

        private async void DoEditTreeCatalogCommand(TreeCatalog element)
        {
            if (element is null)
            {
                return;
            }

            var r = await SingleText("新建文件夹", "输入要创建的文件夹名字");

            if (!r.IsFinished)
            {
                return;
            }

            var oldName = element.Name;
            var newName = r.Value;

            if (!NameMap.Add(newName))
            {
                await Danger(TitleSR.DangerOperation, "名字重复");
                return;
            }

            NameMap.Remove(oldName);
            element.Name = newName;

            //
            //
            
            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);
        }

        private async void DoShiftUpTreeCatalogCommand(TreeCatalog element)
        {
            if (element is null)
            {
                return;
            }

            if (element.IsRoot())
            {
                TreeCatalogs.ShiftUp(element, () =>
                {
                    _appCatalogRoot.Catalogs.ShiftUp(element);
                });

                for (var i = 0; i < TreeCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index                = i;
                    _appCatalogRoot.Catalogs[i].Index = i;
                }
            }
            else if (CatalogMap.TryGetValue(element.ParentID, out var parent))
            {

                parent.Children.ShiftUp(element, () =>
                {
                    for (var i = 0; i < parent.Children.Count; i++)
                    {
                        parent.Children[i].Index = i;
                    }
                });
            }


            //
            //
            
            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);
        }

        private async void DoShiftDownTreeCatalogCommand(TreeCatalog element)
        {
            if (element is null)
            {
                return;
            }

            if (element.IsRoot())
            {
                TreeCatalogs.ShiftDown(element, () =>
                {
                    _appCatalogRoot.Catalogs.ShiftDown(element);
                });

                for (var i = 0; i < TreeCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index                = i;
                    _appCatalogRoot.Catalogs[i].Index = i;
                }
            }
            else if (CatalogMap.TryGetValue(element.ParentID, out var parent))
            {

                parent.Children.ShiftDown(element, () =>
                {
                    for (var i = 0; i < parent.Children.Count; i++)
                    {
                        parent.Children[i].Index = i;
                    }
                });
            }


            //
            //
            
            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);
        }

        private async void DoRemoveTreeCatalogCommand(TreeCatalog element)
        {
            if (element is null)
            {
                return;
            }

            if (!await RemoveItem())
            {
                return;
            }

            if (element.IsRoot())
            {
                TreeCatalogs.Remove(element);
                _appCatalogRoot.Catalogs.Remove(element);


                for (var i = 0; i < TreeCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index                = i;
                    _appCatalogRoot.Catalogs[i].Index = i;
                }
            }
            else if (CatalogMap.TryGetValue(element.ParentID, out var parent))
            {
                parent.Children.Remove(element);
                _appCatalogRoot.Catalogs.Remove(element);

                for (var i = 0; i < parent.Children.Count; i++)
                {
                    parent.Children[i].Index = i;
                }

                //
                //
                var removeRecursive = await DangerOperation(TitleSR.DangerOperation, TextSR.Remove_Item_Recursive);
                
                //
                //
                RemoveRecursiveOrAppendToParent(removeRecursive, element, parent);
            }


            //
            //
            
            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);

        }

        private void RemoveRecursiveOrAppendToParent(bool removeRecursive, TreeCatalog element, TreeCatalog parent)
        {
            var pending = new Queue<TreeCatalog>(64);
            var list    = new List<TreeCatalog>(64);
                
            pending.Enqueue(element);

            if (removeRecursive)
            {
                while (pending.Count > 0)
                {
                    //
                    //
                    var current = pending.Dequeue();

                    if (current.Children is not null && current.Children.Count > 0)
                    {
                        foreach (var child in current.Children)
                        {
                            pending.Enqueue(child);
                            list.Add(child);
                        }
                        
                        //
                        //
                        current.Children.Clear();
                    }
                }
                
                _appCatalogRoot.Catalogs.RemoveMany(list, false);
            }
            else
            {
                //
                //
                parent.Children.AddMany(element.Children);
               
            }
        }
        
        //-------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------
        public TreeCatalog CurrentTreeCatalog
        {
            get => _currentTreeCatalog;
            set
            {
                SetValue(ref _currentTreeCatalog, value);

                if (_currentTreeCatalog is not null && _currentTreeCatalog.UseCustomType)
                {
                    CurrentTreeCatalogCustomTemplate = InstanceTemplates.FirstOrDefault(x => x.CustomType == _currentTreeCatalog.CustomType);
                }
                else
                {
                    CurrentTreeCatalogCustomTemplate = null;
                }
                RaiseUpdated(nameof(IsVisible));
                RaiseUpdated(nameof(TreeCatalogName));
            }
        }

        public InstanceTemplate CurrentTreeCatalogCustomTemplate
        {
            get => _currentTreeCatalogCustomTemplate;
            set
            {
                if (CurrentTreeCatalog is null)
                {
                    return;
                }

                SetValue(ref _currentTreeCatalogCustomTemplate, value);

                if (_currentTreeCatalogCustomTemplate is null)
                {
                    return;
                }

                //
                //
                CurrentTreeCatalog.UseCustomType = _currentTreeCatalogCustomTemplate.UseCustomType;
                CurrentTreeCatalog.CustomType    = _currentTreeCatalogCustomTemplate.CustomType;
                
                //
                //
                RaiseUpdated(nameof(CurrentTreeCatalogCustomType));
                RaiseUpdated(nameof(CurrentTreeCatalogUseCustomType));
            }
        }

        public string CurrentTreeCatalogCustomType
        {
            get => CurrentTreeCatalog?.CustomType;
            set
            {
                CurrentTreeCatalog.CustomType = value;
                RaiseUpdated();
            }
        }

        public bool CurrentTreeCatalogUseCustomType
        {
            get => CurrentTreeCatalog?.UseCustomType ?? false;
            set
            {
                if(CurrentTreeCatalog is null)
                {
                    return;
                }

                CurrentTreeCatalog.UseCustomType = value;
                AfterUseCustomType(value);
                RaiseUpdated();
            }
        }

        public string TreeCatalogName
        {
            get
            {
                if (_currentTreeCatalog is not null)
                {
                    return _currentTreeCatalog.Name;
                }

                return string.Empty;
            }
            set
            {

                if (_currentTreeCatalog is not null)
                {
                    _currentTreeCatalog.Name = value;

                    if (CatalogMap.TryGetValue(_currentTreeCatalog.Id, out var usingCatalog))
                    {
                        usingCatalog.Name = value;
                    }


                    //
                    //
                    Save();
                }
            }
        }
        
        public bool IsVisible
        {
            get
            {
                if (_currentTreeCatalog is not null)
                {
                    return _currentTreeCatalog.IsVisible;
                }

                return false;
            }
            set
            {

                if (_currentTreeCatalog is not null)
                {
                    _currentTreeCatalog.IsVisible = value;

                    //
                    //
                    Save();
                }

                RaiseUpdated();
            }
        }

        public ICommandEX NewTreeCatalogCommand       { get; }
        public ICommandEX EditTreeCatalogCommand      { get; }
        public ICommandEX MoveTreeCatalogCommand      { get; }
        public ICommandEX ShiftUpTreeCatalogCommand   { get; }
        public ICommandEX ShiftDownTreeCatalogCommand { get; }
        public ICommandEX RemoveTreeCatalogCommand    { get; }
        public ICommandEX ApplyCatalogChangedCommand  { get; }

        public ObservableCollection<TreeCatalog> TreeCatalogs { get; }
    }
}